import sys
sys.path.append("..")
import pyrtl
from  pyrtl import GPUSim
import or1200_definitions

dw = or1200_definitions.OR1200_OPERAND_WIDTH
aw = or1200_definitions.OR1200_OPERAND_WIDTH

class Or1200wbbiu(object):
    def __init__(self):
        # RISC clock, reset and clock control
        # self.clk = pyrtl.Input(bitwidth=1, name='clk')  # RISC clock
        self.rst = pyrtl.Input(bitwidth=1, name='rst')  # RISC reset
        self.clmode = pyrtl.Input(bitwidth=2, name='clmode')    # 00 WB=RISC, 01 WB=RISC/2, 10 N/A, 11 WB=RISC/4

        # WISHBONE interface
        self.wb_clk_i = pyrtl.Input(bitwidth=1, name='wb_clk_i')    # clock input
        self.wb_rst_i = pyrtl.Input(bitwidth=1, name='wb_rst_i')    # reset input
        self.wb_ack_i = pyrtl.Input(bitwidth=1, name='wb_ack_i')    # normal termination
        self.wb_err_i = pyrtl.Input(bitwidth=1, name='wb_err_i')    # termination w/ error
        self.wb_rty_i = pyrtl.Input(bitwidth=1, name='wb_rty_i')    # termination w/ retry
        self.wb_dat_i = pyrtl.Input(bitwidth=dw, name='wb_dat_i')   # input data bus

        #self.wb_cyc_o = pyrtl.Output(bitwidth=1, name='wb_cyc_o')   # cycle valid output
        #self.wb_adr_o = pyrtl.Output(bitwidth=aw, name='wb_adr_o')  #  address bus outputs
        #self.wb_stb_o = pyrtl.Output(bitwidth=1, name='wb_stb_o')   # strobe output
        #self.wb_we_o = pyrtl.Output(bitwidth=4, name='wb_we_o')     # indicates write transfer
        #self.wb_sel_o = pyrtl.Output(bitwidth=dw, name='wb_sel_o')  # byte select outputs
        #self.wb_dat_o = pyrtl.Output(bitwidth=1, name='wb_dat_o')   # output data bus
        #self.wb_cab_o = pyrtl.Output(bitwidth=1, name='wb_cab_o')   # consecutive address burst

        # Internal RISC interface
        self.biu_dat_i = pyrtl.Input(bitwidth=dw, name='biu_dat_i')     # input data bus
        self.biu_adr_i = pyrtl.Input(bitwidth=aw, name='biu_adr_i')     # address bus
        self.biu_cyc_i = pyrtl.Input(bitwidth=1, name='biu_cyc_i')      # WB cycle
        self.biu_stb_i = pyrtl.Input(bitwidth=1, name='biu_stb_i')      # WB strobe
        self.biu_we_i = pyrtl.Input(bitwidth=1, name='biu_we_i')        # WB strobe
        self.biu_cab_i = pyrtl.Input(bitwidth=1, name='biu_cab_i')      # CAB input
        self.biu_sel_i = pyrtl.Input(bitwidth=4, name='biu_sel_i')      # byte selects

        self.biu_dat_o = pyrtl.WireVector(bitwidth=32, name='biu_selbiu_dat_o_i')   # output data bus
        self.biu_ack_o = pyrtl.WireVector(bitwidth=1, name='biu_ack_o')             # ack output
        self.biu_err_o = pyrtl.WireVector(bitwidth=1, name='biu_err_o')             #  err output

        # Registers
        self.valid_div = pyrtl.WireVector(bitwidth=2, name='valid_div')
        ## OR1200_REGISTERED_OUTPUTS is True in or1200_definitions, so:
        self.wb_adr_o = pyrtl.Register(bitwidth=aw, name='wb_adr_o')
        self.wb_cyc_o = pyrtl.Register(bitwidth=1, name='wb_cyc_o')
        self.wb_stb_o = pyrtl.Register(bitwidth=1, name='wb_stb_o')
        self.wb_we_o = pyrtl.WireVector(bitwidth=1, name='wb_we_o')
        self.wb_sel_o = pyrtl.Register(bitwidth=4, name='wb_sel_o')

        ## OR1200_WB_CAB is True in or1200_definitions, so:
        self.wb_cab_o = pyrtl.Register(bitwidth=1, name='wb_cab_o')

        self.wb_dat_o = pyrtl.Register(bitwidth=1, name='wb_dat_o')

        ## OR1200_REGISTERED_INPUTS is False in or1200_definitions, so:
        self.long_ack_o = pyrtl.WireVector(bitwidth=1, name='long_ack_o')
        self.long_err_o = pyrtl.WireVector(bitwidth=1, name='long_err_o')

        self.aborted = pyrtl.WireVector(bitwidth=1, name='aborted')
        self.aborted_r = pyrtl.Register(bitwidth=1, name='aborted_r')
        self.retry = pyrtl.WireVector(bitwidth=1, name='retry')

        # appendix
        #self.wb_cti_o = pyrtl.Register(bitwidth=3, name='wb_cti_o')
        #self.burst_len = pyrtl.Register(bitwidth=2, name='burst_len')

        ###################################################################
        # initialize all the parts
        address_bus  = Address_bus()
        output_data_bus = Output_data_bus()
        risc_clock = Risc_clock()
        abortedTransfers = AbortedTransfers()
        wb_cyc_o = Wb_cyc_o()
        wb_stb_o = Wb_stb_o()
        wb_we_o = Wb_we_o()
        wb_sel_o =Wb_sel_o()
        wb_cab_o =Wb_cab_o()
        # wb_Cti_o = Wb_Cti_o()

        # establish connection relations for Address bus
        self.wb_adr_o.next <<= address_bus.wb_adr_o
        # address_bus.wb_clk_i <<= self.wb_clk_i
        address_bus.wb_rst_i <<= self.wb_rst_i
        address_bus.biu_cyc_i <<= self.biu_cyc_i
        address_bus.biu_stb_i <<= self.biu_stb_i
        address_bus.wb_ack_i <<= self.wb_ack_i
        address_bus.aborted <<= self.aborted
        address_bus.wb_stb_o <<= self.wb_stb_o

        # Input data bus
        # OR1200_REGISTERED_INPUTS is nit defined
        self.biu_dat_o <<= self.wb_dat_i

        # establish connection relations for Output data bus
        self.wb_dat_o.next <<= output_data_bus.wb_dat_o
        # output_data_bus.wb_clk_i <<= self.wb_clk_i
        output_data_bus.wb_rst_i <<= self.wb_rst_i
        output_data_bus.biu_cyc_i <<= self.biu_cyc_i
        output_data_bus.biu_stb_i <<= self.biu_stb_i
        output_data_bus.wb_ack_i <<= self.wb_ack_i
        output_data_bus.aborted <<= self.aborted
        output_data_bus.biu_dat_i <<= self.biu_dat_i

        # establish connection relations for RISC clock
        self.valid_div <<= risc_clock.valid_div
        risc_clock.rst <<= self.rst

        # biu_ack_o is one RISC clock cycle long long_ack_o.
        # long_ack_o is one, two or four RISC clock cycles long because
        # WISHBONE can work at 1, 1/2 or 1/4 RISC clock.
        self.biu_ack_o <<= self.long_ack_o & (self.valid_div[0] | (~self.clmode[0]))

        # long_ack_to
        # OR1200_REGISTERED_INPUTS is not defined
        self.long_ack_o <<= self.wb_ack_i & (~self.aborted_r)

        # biu_err_o is one RISC clock cycle long long_err_o.
        # // long_err_o is one, two or four RISC clock cycles long because
        # // WISHBONE can work at 1, 1/2 or 1/4 RISC clock.
        self.biu_err_o <<= self.long_err_o & (self.valid_div[0] | (~self.clmode[0]))

        # Error termination
        # long_err_o
        self.long_err_o <<= self.wb_err_i & (~self.aborted_r)

        # Retry counter
        # OR1200_WB_RETRY is not defined.
        self.retry <<= pyrtl.Const(0b0, bitwidth=1)

        # Graceful completion of aborted transfers
        # Assert 'aborted' when 1) current transfer is in progress (wb_stb_o; which
        # // we know is only asserted together with wb_cyc_o) 2) and in next WB clock cycle
        # // wb_stb_o would be deasserted (biu_cyc_i and biu_stb_i are low) 3) and
        # // there is no termination of current transfer in this WB clock cycle (wb_ack_i
        # // and wb_err_i are low).
        # // 'aborted_r' is registered 'aborted' and extended until this "aborted" transfer
        # // is properly terminated with wb_ack_i/wb_err_i.
        self.aborted <<= self.wb_stb_o & (~(self.biu_cyc_i & self.biu_stb_i)) & (~(self.wb_ack_i | self.wb_err_i))

        # establish connection relations for aborted transfers
        self.aborted_r.next <<= abortedTransfers.aborted_r
        # abortedTransfers.wb_clk_i <<= self.wb_clk_i
        abortedTransfers.wb_rst_i <<= self.wb_rst_i
        abortedTransfers.wb_ack_i <<= self.wb_ack_i
        abortedTransfers.wb_err_i <<= self.wb_err_i
        abortedTransfers.aborted <<= self.aborted

        # establish connection relations for WB cyc_o
        self.wb_cyc_o.next <<= wb_cyc_o.wb_cyc_o
        # wb_cyc_o.wb_clk_i <<= self.wb_clk_i
        wb_cyc_o.wb_rst_i <<= self.wb_rst_i
        wb_cyc_o.biu_cyc_i <<= self.biu_cyc_i
        wb_cyc_o.wb_ack_i <<= self.wb_ack_i
        wb_cyc_o.retry <<= self.retry
        wb_cyc_o.aborted <<= self.aborted
        wb_cyc_o.biu_cab_i <<= self.biu_cab_i

        # establish connection relations for WB stb_o
        self.wb_stb_o.next <<= wb_stb_o.wb_stb_o
        # wb_stb_o.wb_clk_i <<= self.wb_clk_i
        wb_stb_o.wb_rst_i <<= self.wb_rst_i
        wb_stb_o.biu_cyc_i <<= self.biu_cyc_i
        wb_stb_o.biu_stb_i <<= self.biu_stb_i
        wb_stb_o.wb_ack_i <<= self.wb_ack_i
        wb_stb_o.retry <<= self.retry
        wb_stb_o.aborted <<= self.aborted

        # establish connection relations for WB we_o
        self.wb_we_o <<= wb_we_o.wb_we_o
        # wb_we_o.wb_clk_i <<= self.wb_clk_i
        wb_we_o.wb_rst_i <<= self.wb_rst_i
        wb_we_o.biu_cyc_i <<= self.biu_cyc_i
        wb_we_o.biu_stb_i <<= self.biu_stb_i
        wb_we_o.biu_we_i <<= self.biu_we_i
        wb_we_o.aborted <<= self.aborted
        
        self.wb_we_o = self.biu_cyc_i & self.biu_stb_i & self.biu_we_i
        
        # establish connection relations for WB sel_o
        self.wb_sel_o.next <<= wb_sel_o.wb_sel_o
        # wb_sel_o.wb_clk_i <<= self.wb_clk_i
        wb_sel_o.wb_rst_i <<= self.wb_rst_i
        wb_sel_o.biu_sel_i <<= self.biu_sel_i
        
        # establish connection relations for WB cab_o
        self.wb_cab_o.next <<= wb_cab_o.wb_cab_o
        # wb_cab_o.wb_clk_i <<= self.wb_clk_i
        wb_cab_o.wb_rst_i <<= self.wb_rst_i
        wb_cab_o.biu_cab_i <<= self.biu_cab_i

        # establish connection relations for WB cti_o
        # self.wb_cti_o.next <<= wb_Cti_o.wb_cti_o
        
        # wb_Cti_o.wb_rst_i <<= self.wb_rst_i
        # wb_Cti_o.biu_cab_i <<= self.biu_cab_i
        # wb_Cti_o.burst_len <<= self.burst_len
        # wb_Cti_o.wb_ack_i <<= self.wb_ack_i

        # self.wb_bte_o = pyrtl.Const(0b01, bitwidth=2)
        
#  Address bus
class Address_bus(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_cyc_i = pyrtl.WireVector(bitwidth=1)  # WB cycle
        self.biu_stb_i = pyrtl.WireVector(bitwidth=1)  # WB strobe
        self.wb_ack_i = pyrtl.WireVector(bitwidth=1)  # normal termination
        self.aborted = pyrtl.WireVector(bitwidth=1)
        self.wb_stb_o = pyrtl.WireVector(bitwidth=1)  # strobe output

        self.wb_adr_o = pyrtl.WireVector(bitwidth=aw)  # address bus outputs

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_adr_o |= pyrtl.Const(aw * 0b0, bitwidth=aw)     # wb_adr_o <= #1 {aw{1'b0}}
            with (self.biu_cyc_i & self.biu_stb_i) & (~self.wb_ack_i) & \
                 (~self.aborted) & (~(self.wb_stb_o & (~self.wb_ack_i))):
                self.wb_adr_o |= self.biu_stb_i                     # wb_adr_o <= #1 biu_adr_i



# Output data bus
class Output_data_bus(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_cyc_i = pyrtl.WireVector(bitwidth=1)  # WB cycle
        self.biu_stb_i = pyrtl.WireVector(bitwidth=1)  # WB strobe
        self.wb_ack_i = pyrtl.WireVector(bitwidth=1)  # normal termination
        self.aborted = pyrtl.WireVector(bitwidth=1)
        self.biu_dat_i = pyrtl.WireVector(bitwidth=dw)  # input data bus

        self.wb_dat_o = pyrtl.WireVector(bitwidth=1)

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_dat_o |= pyrtl.Const(dw * 0b0, bitwidth=dw)     #@ wb_dat_o <= #1 {dw{1'b0}}
            with (self.biu_cyc_i & self.biu_stb_i) & (~self.wb_ack_i) & (~self.aborted):
                self.wb_dat_o |= self.biu_dat_i        # wb_dat_o <= #1 biu_dat_i

# Valid_div counts RISC clock cycles by modulo 4
# and is used to synchronize external WB i/f to
# RISC clock
class Risc_clock(object):
    def __init__(self):
        # self.clk = pyrtl.Input(bitwidth=1, name='clk')  # RISC clock
        self.rst = pyrtl.WireVector(bitwidth=1)  # RISC reset

        self.valid_div = pyrtl.Register(bitwidth=2)

        with pyrtl.conditional_assignment:
            with self.rst:
                self.valid_div.next |= pyrtl.Const(0b0, bitwidth=2) # valid_div <= #1 2'b0
            with pyrtl.otherwise:
                self.valid_div.next |= self.valid_div + pyrtl.Const(0b1, bitwidth=1)     # valid_div <= #1 valid_div + 1'd1

# Graceful completion of aborted transfers
# //
# // Assert 'aborted' when 1) current transfer is in progress (wb_stb_o; which
# // we know is only asserted together with wb_cyc_o) 2) and in next WB clock cycle
# // wb_stb_o would be deasserted (biu_cyc_i and biu_stb_i are low) 3) and
# // there is no termination of current transfer in this WB clock cycle (wb_ack_i
# // and wb_err_i are low).
# // 'aborted_r' is registered 'aborted' and extended until this "aborted" transfer
# // is properly terminated with wb_ack_i/wb_err_i.

class AbortedTransfers(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.wb_ack_i = pyrtl.WireVector(bitwidth=1)  # normal termination
        self.wb_err_i = pyrtl.WireVector(bitwidth=1)  # termination w/ error
        self.aborted = pyrtl.WireVector(bitwidth=1)

        self.aborted_r = pyrtl.WireVector(bitwidth=1)

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.aborted_r |= pyrtl.Const(0b0, bitwidth=1)
            with self.wb_ack_i | self.wb_err_i:
                self.aborted_r |= pyrtl.Const(0b0, bitwidth=1)
            with self.aborted:
                self.aborted_r |= pyrtl.Const(0b1, bitwidth=1)

# WB cyc_o
# //
# // Either 1) normal transfer initiated by biu_cyc_i (and biu_cab_i if
# // bursts are enabled) and possibly suspended by 'retry'
# // or 2) extended "aborted" transfer

class Wb_cyc_o(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_cyc_i = pyrtl.WireVector(bitwidth=1)  # WB cycle
        self.wb_ack_i = pyrtl.WireVector(bitwidth=1)  # normal termination
        self.retry = pyrtl.WireVector(bitwidth=1)
        self.aborted = pyrtl.WireVector(bitwidth=1)
        self.biu_cab_i = pyrtl.WireVector(bitwidth=1)  # CAB input

        self.wb_cyc_o = pyrtl.WireVector(bitwidth=1)  # cycle valid output

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_cyc_o |= pyrtl.Const(0b0, bitwidth=1)   # wb_cyc_o <= #1 1'b0
            with pyrtl.otherwise:
                self.wb_cyc_o |= self.biu_cyc_i & (~self.wb_ack_i) & (~self.retry) | \
                                 self.biu_cab_i | self.aborted & (~self.wb_ack_i)
                # wb_cyc_o <= #1 biu_cyc_i & ~wb_ack_i & ~retry | biu_cab_i | aborted & ~wb_ack_i

# WB stb_o
#
class Wb_stb_o(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_cyc_i = pyrtl.WireVector(bitwidth=1)  # WB cycle
        self.biu_stb_i = pyrtl.WireVector(bitwidth=1)  # WB strobe
        self.wb_ack_i = pyrtl.WireVector(bitwidth=1)  # normal termination
        self.retry = pyrtl.WireVector(bitwidth=1)
        self.aborted = pyrtl.WireVector(bitwidth=1)

        self.wb_stb_o = pyrtl.WireVector(bitwidth=1)  # strobe output

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_stb_o |= pyrtl.Const(0b0, bitwidth=1)   # wb_stb_o <= #1 1'b0
            with pyrtl.otherwise:
                self.wb_stb_o |= (self.biu_cyc_i & self.biu_stb_i) & (~self.wb_ack_i) & \
                                 (~self.retry) | self.aborted & (~self.wb_ack_i)
                # wb_stb_o <= #1 (biu_cyc_i & biu_stb_i) & ~wb_ack_i & ~retry | aborted & ~wb_ack_i
        self.wb_stb_o = self.biu_cyc_i & self.biu_stb_i


# WB we_o
#
class Wb_we_o(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_cyc_i = pyrtl.WireVector(bitwidth=1)  # WB cycle
        self.biu_stb_i = pyrtl.WireVector(bitwidth=1)  # WB strobe
        self.biu_we_i = pyrtl.WireVector(bitwidth=1)  # WB strobe
        self.aborted = pyrtl.WireVector(bitwidth=1)

        self.wb_we_o = pyrtl.Register(bitwidth=4)  # indicates write transfer

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_we_o.next |= pyrtl.Const(0b0, bitwidth=1)    # wb_we_o <= #1 1'b0
            with pyrtl.otherwise:
                self.wb_we_o.next |= self.biu_cyc_i & self.biu_stb_i & self.biu_we_i \
                                | self.aborted & self.wb_we_o
                # wb_we_o <= #1 biu_cyc_i & biu_stb_i & biu_we_i | aborted & wb_we_o
        


# WB stb_o
#
class Wb_sel_o(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_sel_i = pyrtl.WireVector(bitwidth=4)  # byte selects

        self.wb_sel_o = pyrtl.WireVector(bitwidth=dw)  # byte select outputs

        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_sel_o |= pyrtl.Const(0b0000, bitwidth=4)    # wb_sel_o <= #1 4'b0000
            with pyrtl.otherwise:
                self.wb_sel_o |= self.biu_sel_i         # wb_sel_o <= #1 biu_sel_i
        self.wb_sel_o = self.biu_sel_i

# WB cab_o
# 
class Wb_cab_o(object):
    def __init__(self):
        # self.wb_clk_i = pyrtl.WireVector(bitwidth=1, name='wb_clk_i')  # clock input
        self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        self.biu_cab_i = pyrtl.WireVector(bitwidth=1)  # CAB input
        
        self.wb_cab_o = pyrtl.WireVector(bitwidth=1)
        
        with pyrtl.conditional_assignment:
            with self.wb_rst_i:
                self.wb_cab_o |= pyrtl.Const(0b0, bitwidth=1)    # wb_cab_o <= #1 1'b0
            with pyrtl.otherwise:
                self.wb_cab_o |= self.biu_cab_i         # wb_cab_o <= #1 biu_cab_i
        self.wb_sel_o = self.biu_cab_i
        
    
# WB cti_o
# 
# class Wb_Cti_o(object):
    # def __init__(self):
       
        # self.wb_rst_i = pyrtl.WireVector(bitwidth=1)  # reset input
        # self.biu_cab_i = pyrtl.WireVector(bitwidth=1)  # CAB input
        # self.burst_len = pyrtl.WireVector(bitwidth=2)
        # self.wb_ack_i = pyrtl.WireVector(bitwidth=1)  # normal termination

        # self.wb_cti_o = pyrtl.WireVector(bitwidth=3)
        
        # with pyrtl.conditional_assignment:
            # with self.wb_rst_i:
                # self.wb_cti_o |= pyrtl.Const(0b000, bitwidth=3)
            # with (self.biu_cab_i.__and__(self.burst_len[1])):
                # self.wb_cti_o = pyrtl.Const(0b010, bitwidth=3)
            # with (self.biu_cab_i.__and__(self.wb_ack_i)):
                # self.wb_cti_o = pyrtl.Const(0b111, bitwidth=3)
                    


if __name__ == '__main__':
    or1200wbbiu = Or1200wbbiu()
    sim = pyrtl.GPUSim_now.GPUSim(65536)
    sim.create_dll('wbbiu.cu')
    print(pyrtl.working_block())